﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace System
{
    public class EncryptHelper
    {
        private static char[] base64CodeArray = new char[]
        {
         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
         '0', '1', '2', '3', '4',  '5', '6', '7', '8', '9', '+', '/', '='
        };

        const string Key = "rew@#$f43r43%#43123s";
        const string IV = "e74@#43454..-+234$#fds";

        public static SecureString SecurityKey = new SecureString();
        public static void DESSetKey()
        {
            SecurityKey.AppendChar('E');
            SecurityKey.AppendChar('C');
            SecurityKey.AppendChar('O');
            SecurityKey.AppendChar('M');
            SecurityKey.AppendChar('B');
            SecurityKey.AppendChar('A');
            SecurityKey.AppendChar('O');
        }

        public static string FromSecurityString(SecureString ss)
        {
            return Marshal.PtrToStringBSTR(Marshal.SecureStringToBSTR(SecurityKey));
        }

        #region RAS加解密
        /// <summary>
        /// RSA算法加密
        /// </summary>
        /// <param name="express"></param>
        /// <returns></returns>
        public static string RSAEncryption(string express)
        {
            CspParameters param = new CspParameters();
            param.KeyContainerName = "rsa_hs";//密匙容器的名称，保持加密解密一致才能解密成功
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(param))
            {
                byte[] plaindata = Encoding.Default.GetBytes(express);//将要加密的字符串转换为字节数组
                byte[] encryptdata = rsa.Encrypt(plaindata, false);//将加密后的字节数据转换为新的加密字节数组
                return Convert.ToBase64String(encryptdata);//将加密后的字节数组转换为字符串
            }
        }

        /// <summary>
        /// RSA加密对象
        /// </summary>
        /// <param name="express"></param>
        /// <returns></returns>
        public static string RSAEncryption(object express)
        {
            CspParameters param = new CspParameters();
            param.KeyContainerName = "rsa_hs";//密匙容器的名称，保持加密解密一致才能解密成功
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(param))
            {
                MemoryStream stream = new MemoryStream();
                IFormatter formatter = new BinaryFormatter();
                formatter.Serialize(stream, express);
                stream.Position = 0;
                byte[] data = new byte[stream.Length];
                stream.Read(data, 0, data.Length);
                //byte[] plaindata = Encoding.Default.GetBytes(express);//将要加密的字符串转换为字节数组
                //byte[] encryptdata = rsa.Encrypt(plaindata, false);//将加密后的字节数据转换为新的加密字节数组
                byte[] encryptdata = rsa.Encrypt(data, false);
                return Convert.ToBase64String(encryptdata);//将加密后的字节数组转换为字符串
            }
        }

        /// <summary>
        /// RSA解密
        /// </summary>
        /// <param name="ciphertext"></param>
        /// <returns></returns>
        public static string RSADecrypt(string ciphertext)
        {
            CspParameters param = new CspParameters();
            param.KeyContainerName = "rsa_hs";
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(param))
            {
                byte[] encryptdata = Convert.FromBase64String(ciphertext);
                byte[] decryptdata = rsa.Decrypt(encryptdata, false);
                return Encoding.Default.GetString(decryptdata);
            }
        }

        /// <summary>
        /// RSA解密对象
        /// </summary>
        /// <param name="ciphertext"></param>
        /// <returns></returns>
        public static object RSADecryptObj(string ciphertext)
        {
            CspParameters param = new CspParameters();
            param.KeyContainerName = "rsa_hs";
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(param))
            {
                byte[] encryptdata = Convert.FromBase64String(ciphertext);
                byte[] decryptdata = rsa.Decrypt(encryptdata, false);
                //return Encoding.Default.GetString(decryptdata);
                MemoryStream stream = new MemoryStream();
                IFormatter formatter = new BinaryFormatter();
                stream.Write(decryptdata, 0, decryptdata.Length);
                stream.Position = 0;
                object obj = formatter.Deserialize(stream);
                return obj;
            }
        } 
        #endregion

        #region DES加解密
        /// <summary>
        /// DES字符串加密
        /// </summary>
        /// <param name="_strQ"></param>
        /// <param name="strKey"></param>
        /// <returns></returns>
        public static string DESEncrypt(string _strQ, string strKey)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(_strQ);
            MemoryStream ms = new MemoryStream();
            DESCryptoServiceProvider tdes = new DESCryptoServiceProvider();
            CryptoStream encStream = new CryptoStream(ms, tdes.CreateEncryptor(Encoding.UTF8.GetBytes(strKey), Encoding.UTF8.GetBytes(strKey)), CryptoStreamMode.Write);
            encStream.Write(buffer, 0, buffer.Length);
            encStream.FlushFinalBlock();
            return Convert.ToBase64String(ms.ToArray()).Replace("+", "%");
        }

        /// <summary>
        /// DES字符串解密
        /// </summary>
        /// <param name="_strQ"></param>
        /// <param name="strKey"></param>
        /// <returns></returns>
        public static string DESDecrypt(string _strQ, string strKey)
        {
            _strQ = _strQ.Replace("%", "+");
            byte[] buffer = Convert.FromBase64String(_strQ);
            MemoryStream ms = new MemoryStream();
            DESCryptoServiceProvider tdes = new DESCryptoServiceProvider();
            CryptoStream encStream = new CryptoStream(ms, tdes.CreateDecryptor(Encoding.UTF8.GetBytes(strKey), Encoding.UTF8.GetBytes(strKey)), CryptoStreamMode.Write);
            encStream.Write(buffer, 0, buffer.Length);
            encStream.FlushFinalBlock();
            return Encoding.UTF8.GetString(ms.ToArray());
        } 
        #endregion

        #region MD5加密
        /// <summary>
        /// MD5
        /// </summary>
        /// <param name="express"></param>
        /// <returns></returns>
        public static string MD5(string express)
        {
            if (string.IsNullOrEmpty(express))
            {
                return string.Empty;
            }

            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] palindata = Encoding.Default.GetBytes(express);//将要加密的字符串转换为字节数组
            byte[] encryptdata = md5.ComputeHash(palindata);//将字符串加密后也转换为字符数组
            return BitConverter.ToString(encryptdata, 0).Replace("-", string.Empty);
        }

        public static string MD5ThenBase64(string express)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] palindata = Encoding.Default.GetBytes(express);//将要加密的字符串转换为字节数组
            byte[] encryptdata = md5.ComputeHash(palindata);//将字符串加密后也转换为字符数组
            return Convert.ToBase64String(encryptdata);//将加密后的字节数组转换为加密字符串
        } 
        #endregion

        #region Base64编解码
        /// <summary>
        /// Base64加密
        /// </summary>
        /// <param name="code_type"></param>
        /// <param name="code"></param>
        /// <returns></returns>
        public static string EncodeBase64(string code_type, string code)
        {
            string encode = "";
            byte[] bytes = Encoding.GetEncoding(code_type).GetBytes(code);
            try
            {
                encode = Convert.ToBase64String(bytes);
            }
            catch
            {
                encode = code;
            }
            return encode;
        }

        /// <summary>
        /// Base64解密
        /// </summary>
        /// <param name="code_type"></param>
        /// <param name="code"></param>
        /// <returns></returns>
        public static string DecodeBase64(string code_type, string code)
        {
            string decode = "";

            try
            {
                byte[] bytes;// = Convert.FromBase64String(code);
                if (IsBase64(code, out bytes))
                {
                    decode = Encoding.GetEncoding(code_type).GetString(bytes);
                }
                else
                {
                    decode = code;
                }
            }
            catch
            {
                decode = code;
            }

            return decode;
        }

        /// <summary>
        /// 是否base64字符串
        /// </summary>
        /// <param name="base64Str">要判断的字符串</param>
        /// <param name="bytes">字符串转换成的字节数组</param>
        /// <returns></returns>
        public static bool IsBase64(string base64Str, out byte[] bytes)
        {
            //string strRegex = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$";
            bytes = null;
            if (string.IsNullOrEmpty(base64Str))
                return false;
            else
            {
                if (base64Str.Contains(","))
                    base64Str = base64Str.Split(',')[1];
                if (base64Str.Length % 4 != 0)
                    return false;
                if (base64Str.Any(c => !base64CodeArray.Contains(c)))
                    return false;
            }
            try
            {
                bytes = Convert.FromBase64String(base64Str);
                return true;
            }
            catch (FormatException)
            {
                return false;
            }
        } 
        #endregion

        #region AES加解密

        public static string AESEncrypt(string originStr, string key = Key)
        {
            try
            {
                using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider())
                {
                    //aes的key和iv有长度要求
                    aes.Key = Encoding.Unicode.GetBytes(key).Take(32).ToArray();
                    aes.IV = Encoding.Unicode.GetBytes(IV).Take(16).ToArray();
                    var enc = aes.CreateEncryptor(aes.Key, aes.IV);
                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (CryptoStream cs = new CryptoStream(ms, enc, CryptoStreamMode.Write))
                        {
                            var bts = Encoding.Unicode.GetBytes(originStr);
                            cs.Write(bts, 0, bts.Length);
                        }
                        //用Base64编码存储加密后的字符串；其他编码格式可能因不可显示字符而造成数据丢失
                        return Convert.ToBase64String(ms.ToArray());
                    }
                }
            }
            catch (Exception ex)
            {


            }
            return originStr;
        }

        public static string AESDecrypt(string encryptedStr, string key = Key)
        {
            try
            {
                using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider())
                {
                    aes.Key = Encoding.Unicode.GetBytes(key).Take(32).ToArray();
                    aes.IV = Encoding.Unicode.GetBytes(IV).Take(16).ToArray();
                    var enc = aes.CreateDecryptor(aes.Key, aes.IV);
                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (CryptoStream cs = new CryptoStream(ms, enc, CryptoStreamMode.Write))
                        {
                            var bts = Convert.FromBase64String(encryptedStr);
                            cs.Write(bts, 0, bts.Length);
                        }
                        return Encoding.Unicode.GetString(ms.ToArray());
                    }
                }
            }
            catch (Exception ex)
            {
            }
            return encryptedStr;
        }
        #endregion
    }
}
